import { useVirtualizer } from '@tanstack/react-virtual';
import cx from 'classnames';
import React, { useContext, useEffect, useMemo } from 'react';

import { deepClone, isBoolean } from '../../../utils';
import TableRow from './TableRow';

import type { Row, Table } from '@tanstack/react-table';
import type { Context } from '../../context/table';
import type {
  AnyObject,
  ColumnMeta,
  ColumnPinning,
  ColumnPinningInfo,
  DragType,
  Size,
  Sort,
  Sorter,
  TableOnCell,
  TableOnRow,
} from '../../type';

export interface Props<T extends AnyObject, Context = any> {
  prefixCls: string;
  context: React.Context<Context>;
  size?: Size;
  table: Table<T>;
  dragTypes: DragType[];
  columnPinning: ColumnPinning;
  columnPinningInfo: ColumnPinningInfo;
  dataSource: T[];
  bordered?: boolean;
  isShowBoxShadow?: boolean;
  onRow?: TableOnRow<T>;
  onCell?: TableOnCell<T>;
  onChangeDataSource?: (dataSource: T[]) => void;
}
function TableTbody<T extends AnyObject>(props: Props<T>) {
  const { size, table, bordered, prefixCls, dragTypes, context } = props;
  const { isShowBoxShadow, columnPinning, columnPinningInfo, dataSource } =
    props;
  const tbodyRef = React.useRef<HTMLDivElement>(null);
  const columns = table.getVisibleFlatColumns(); // 显示的列
  const {
    table: { columnSorting },
  } = useContext<Context<T>>(context);
  // 优先级排序列
  const sortColumns = useMemo(() => {
    const defaultSorter: Sorter = { multiple: 1 };
    return columns
      .filter((column) => {
        const columnMeta: ColumnMeta<T> = column.columnDef.meta || {};
        return !!columnMeta.sorter;
      })
      .map((column) => {
        const columnMeta: ColumnMeta<T> = column.columnDef.meta || {};
        return {
          id: column.id,
          sorter: isBoolean(columnMeta.sorter)
            ? defaultSorter
            : columnMeta.sorter,
        };
      })
      .sort((a, b) => b.sorter.multiple - a.sorter.multiple);
  }, [columns]);

  useEffect(() => {
    sortData(columnSorting, sortColumns);
  }, [columnSorting]);

  // 多列排序
  const sortData = (
    columnSorting: { [key in string]: Sort },
    sortColumns: { id: string; sorter: Sorter }[],
  ) => {
    const data = deepClone(dataSource);
    const sortFn = (a: T, b: T) => {
      const sortingColumns = sortColumns.filter(({ id }) =>
        ['asce', 'desc'].includes(columnSorting[id]),
      );
      for (let data of sortingColumns) {
        const { id, sorter } = data;
        const sort = columnSorting[id];
        const result = sorter.compare ? sorter.compare(a, b) : a[id] - b[id];
        if (result !== 0) {
          if (sort === 'asce') {
            return result;
          } else if (sort === 'desc') {
            return -result;
          }
        }
      }
    };
    props.onChangeDataSource?.(data.sort(sortFn));
  };

  // 行拖拽排序
  const reorderRow = (draggedRowIndex: number, targetRowIndex: number) => {
    const data = deepClone(dataSource);
    data.splice(targetRowIndex, 0, data.splice(draggedRowIndex, 1)[0] as T);
    props.onChangeDataSource?.(data);
  };

  const rowVirtualizer = useVirtualizer({
    count: dataSource.length,
    getScrollElement: () => tbodyRef.current,
    estimateSize: () => 10,
    overscan: 10,
  });
  const virtualRows = rowVirtualizer.getVirtualItems();
  const { rows } = table.getRowModel();
  const rowsData =
    rows.length > virtualRows.length
      ? rows
      : virtualRows.map((virtualRow) => {
          const { rows } = table.getRowModel();
          const row = rows[virtualRow.index] as Row<T>;
          return row;
        });
  return (
    <div
      className={cx(`${prefixCls}-section`, `${prefixCls}-tbody`)}
      ref={tbodyRef}
    >
      {rowsData.map((row, i) => {
        return (
          <TableRow
            key={i}
            isShowBoxShadow={isShowBoxShadow}
            isCanDrag={dragTypes.includes('row')}
            context={context}
            prefixCls={prefixCls}
            bordered={bordered}
            size={size}
            row={row}
            columnPinning={columnPinning}
            columnPinningInfo={columnPinningInfo}
            reorderRow={reorderRow}
            onRow={props.onRow}
            onCell={props.onCell}
          />
        );
      })}
    </div>
  );
}

export default TableTbody;
